#include "command.h"

#define BUFFERSIZE 4096

//私有通信协议， 因为TCP通信是字节流，没有边界，
//通过私有协议，能让发送接收方遵守确定的边界，接收数据
//定义一个小火车的私有协议
//typedef struct train_t {
  //  int length;
    //char buf[BUFFERSIZE];
//} train_t;


//puts filename , 上传文件到服务器，需要一个用于通信的文件描述符。
//检查本地是否有这样一个文件
int putsfile(command_t* pcom, int fd)
{
    //本函数有两个文件描述符，
    //fdread是打开的本地文件的描述符
    //fd是用作TCP，socket网络通信的文件描述符
    train_t train;  //栈上
    memset(&train, 0, sizeof(train));


    //1、检查本地是否有这个文件，没有打印错误信息
    int fdread = open(pcom->name, O_RDONLY);
    if (-1 == fdread) {
        puts("Do not have this file");
        return -1;
    }
    printf("command：%s\n", pcom->command);
    //2、有这个文件，执行上传
    //此处再把命令传给服务器，不然先发过去了，-------------重要
    //服务器也不知道你这个文件有没有，能不能发过
    //执行send发送命令给服务器-------
    //
    //TCP通信是字节流协议，没有消息边界，不知道读到哪里作为消息的边界------最重要！
    //--发送命令也需要用小火车发送，不然接收端不知道读到哪里作为消息边界，特别是后面又跟数据来时
    
    //1.1、发送命令--用小火车
    train.length = strlen(pcom->command);
    strncpy(train.buf, pcom->command, train.length);

    int ret = sendn(fd, &train, 4 + train.length);  //4,length长度，train.length内容长度
    printf("send ret = %d\n", ret);
    if (-1 == ret) {
        puts("sendn failed 0");
        return -1;
    }

    //1）传文件名
    memset(&train, 0, sizeof(train));

    train.length = strlen(pcom->name);
    strncpy(train.buf, pcom->name, train.length);  //由输入的命令得来的文件名

    //按实际长度传过去的，并不是BUFFERSIZE + 4；
    ret = sendn(fd, &train, 4 + train.length);
    if (-1 == ret) {
        //数据没有传完
        puts("sendn failed 1");
        return -1;
    }

    //2） 传文件长度
    struct stat statbuf;
    memset(&statbuf, 0, sizeof(statbuf));
    ret = fstat(fdread, &statbuf);  //这里应该是打开的本地文件的文件描述符
    if (-1 == ret) {
        perror("fstat");
        return -1;
    }
    printf(">> file length: %ld\n", statbuf.st_size);

    memset(&train, 0, sizeof(train));
    train.length = sizeof(off_t);  //长度信息是off_t类型，//传过去的是字符串格式
    strncpy(train.buf, (char* )&statbuf.st_size, sizeof(off_t));  //TCP字节流，这样传？
    ret = sendn(fd, &train, 4 + train.length);  //socket网络通信的文件描述符
    if (-1 == ret) {
        puts("sendn failed 2");
        return -1;
    }

    //3 传文件
    off_t total = 0;
    while (total < statbuf.st_size) {
        memset(&train, 0, sizeof(train));
        ret = read(fdread, train.buf, BUFFERSIZE);
        if (0 == ret) {
            puts("bigfile send over");
            break;
        }
        ERROR_CHECK(ret, -1, "read");  //不想重写错误判断了
        train.length = ret;  //可能会产生问题-----

        ret = sendn(fd, &train, 4 + train.length);
        //返回的是发送成功的字节数
        if (-1 == ret) {
            puts("sendn failed 3");
            return -1;
        }
        total += train.length;
    }

    //4、打开一个文件描述符，记得关闭文件描述符
    close(fdread);
    return 0;
}

int getsfile(char* filename, int fd)  //自己本地创建一个文件，获得文件描述符
{
    return 0;
}

int sendn(int fd, const void* str, int len)
{
    char*  train= (char* )str;
    int left = len;
    int ret = -1;

    while (left > 0) {
        ret = send(fd, train, left, 0);
        if (-1 == ret) {
            perror("send");
            return -1;
        }
        else {
            train += ret;
            left -= ret;
        }
    }
    return len - left;  //返回的是发送成功的字节数
}
